let angleX = ref (50.)
let angleZ = ref (80.)
let display_option = ref ""
let glob_obj = ref ""
let vertices = ref (Array.make (1000 * 1000) (0.,0.,0.))
let faces = ref []
let alt_list = ref []

(*
let memo_rec yf =
   let h = Hashtbl.create 97 in
   let rec f x =
     try Hashtbl.find h x
     with Not_found ->
       let y = yf f x in
       Hashtbl.add h x y;
       y
   in
   f
 *)
let rec vertex_color color_list alt =
    match color_list with
      | [] -> (255.,255.,255.)
      | (i,(x,y,z))::l when (float_of_int i) = alt -> (x,y,z)
      | (i,(x,y,z))::l -> vertex_color l alt
(*
let vertex2color =
  let f  = vertex_color (Data.fill_acl ()) in
    memo_rec f
 *)
let draw_face = function
  | (a,b,c) -> let (x,alt,z) = !vertices.(a-1) in
      GlDraw.color (vertex_color !alt_list alt);
      GlDraw.vertex3 (!vertices.(a-1));
      let (x,alt,z) = !vertices.(b-1) in
      GlDraw.color (vertex_color !alt_list alt);
      GlDraw.vertex3 (!vertices.(b-1));
      let (x,alt,z) = !vertices.(c-1) in
      GlDraw.color (vertex_color !alt_list alt);
      GlDraw.vertex3 (!vertices.(c-1))
  
let draw_faces () =
  List.iter draw_face !faces 


(* GLGTK *)

let time =
  let start = Unix.gettimeofday () in
    fun () -> Unix.gettimeofday () -. start


let resizeGLScene ~width ~height =
  let ok_height =
    if height = 0 then 1 else height in

  GlDraw.viewport 0 0 width ok_height;

  GlMat.mode `projection;
  GlMat.load_identity ();
  
  GluMat.perspective ~fovy:70.0 
    ~aspect:((float_of_int width)/.(float_of_int ok_height)) ~z:(0.1, 1000.0);

  GluMat.look_at 
    ~eye:(float_of_int (width / -2),float_of_int (height / -2), 0.) 
    ~center:(0., 0.1, 0.) 
    ~up:(-20., 0., 0.); 
 
  GlMat.mode `modelview;
  Gl.enable `depth_test;
  GlMat.load_identity ()



let initGL () =
  GlDraw.shade_model `smooth;
  
  GlClear.color ~alpha:0.0 (0.0, 0.0, 0.0);

  GlClear.depth 1.0;
  Gl.enable `depth_test;
  GlFunc.depth_func `lequal;

  GlMisc.hint `perspective_correction `nicest



let up_cam ev =
  begin
    let k = GdkEvent.Key.keyval ev in
      if k = GdkKeysyms._Up then
        angleZ := !angleZ -. 10.
      else if k =GdkKeysyms. _Down then
        angleZ := !angleZ +. 10.
      else if k = GdkKeysyms._Left then
        angleX := !angleX -. 10.
      else if k = GdkKeysyms._Right then
        angleX := !angleX +. 10.;
      true
  end



let drawGLScene area window () =
  GlClear.clear [`color; `depth];
  GlMat.load_identity ();
                      
  GlMat.rotate ~angle:!angleZ ~x:0. ~y:0. ~z:100. (); 
  GlMat.rotate ~angle:!angleX ~x:0. ~y:100. ~z:0. (); 

  ignore(window#event#add [`KEY_PRESS]);
  ignore(window#event#connect#key_press ~callback:up_cam);


  if !display_option = "wireframe" then
    GlDraw.begins `line_strip
  else if !display_option = "pointsfield" then
    GlDraw.begins `points
  else
    GlDraw.begins `triangles;

  draw_faces ();
 
(*
  GlDraw.color (1.0, 0.0, 0.0);
  GlDraw.vertex3 (0.0, 1.0, 0.0);
  GlDraw.color (0.0, 1.0, 0.0);
  GlDraw.vertex3 (-1.0, -1.0, 1.0);
  GlDraw.color (0.0, 0.0, 1.0);
  GlDraw.vertex3 (1.0, -1.0, 1.0);

  GlDraw.color (1.0, 0.0, 0.0);
  GlDraw.vertex3 (0.0, 1.0, 0.0);
  GlDraw.color (0.0, 0.0, 1.0);
  GlDraw.vertex3 (1.0, -1.0, 1.0);
  GlDraw.color (0.0, 1.0, 0.0);
  GlDraw.vertex3 (1.0, -1.0, -1.0);

  GlDraw.color (1.0, 0.0, 0.0);
  GlDraw.vertex3 (0.0, 1.0, 0.0);
  GlDraw.color (0.0, 1.0, 0.0);
  GlDraw.vertex3 (1.0, -1.0, -1.0);
  GlDraw.color (0.0, 0.0, 1.0);
  GlDraw.vertex3 (-1.0, -1.0, -1.0);

  GlDraw.color (1.0, 0.0, 0.0);
  GlDraw.vertex3 (0.0, 1.0, 0.0);
  GlDraw.color (0.0, 0.0, 1.0);
  GlDraw.vertex3 (-1.0, -1.0, -1.0);
  GlDraw.color (0.0, 1.0, 0.0);
  GlDraw.vertex3 (-1.0, -1.0, 1.0);
 *)
  GlDraw.ends ();

  area#swap_buffers ()



let killGLWindow () =
  () (* do nothing *)

let createGLArea title tmp_alt_list window obj width height bits fullscreen option box =
  let area = GlGtk.area [`DOUBLEBUFFER;`RGBA;`DEPTH_SIZE 16;`BUFFER_SIZE bits]
    ~width:width ~height:height ~packing:box#add () in
  let (tmp_vertices, tmp_faces) = WriteObj.read_obj obj in
    alt_list := tmp_alt_list;
    vertices := tmp_vertices;
    faces := tmp_faces;
    glob_obj := obj;
    display_option := option;

  ignore(GMain.Timeout.add ~ms:20 ~callback:
	   begin fun () ->
	     drawGLScene area window (); true
	   end);

  ignore(area#event#add [`KEY_PRESS]);

  ignore(area#connect#display ~callback:(drawGLScene area window));
  ignore(area#connect#reshape ~callback:resizeGLScene);

  ignore(area#connect#realize ~callback:
	   begin fun () ->
	     initGL ();
	     resizeGLScene width height
	   end);
  area 
(* END *)
